//; ---------------------------------------------------------------------------
//; Object 11 - GHZ bridge
//; ---------------------------------------------------------------------------

#include "bridge.h"
#include "../../collision.h"

#include "../../sprite.h"
#include "../../objectsystemNEWER.h"

#include "../../misc.h"   //CalcSine

extern object *objects;

static object *obj;

//; ---------------------------------------------------------------------------
//; Sprite mappings - GHZ	bridge
//; ---------------------------------------------------------------------------
byte M_Bri_Log[6]    = { 1,
		      0xF8, 5, 0, 0, 0xF8	
}; //; log
byte M_Bri_Stump[11] = { 2,
		      0xF8,   4, 0, 4, 0xF0,
                         0, 0xC, 0, 6, 0xF0
}; //; stump & rope
byte M_Bri_Rope[6]   = { 1,
		      0xFC,   4, 0, 8, 0xF8
}; //; rope only

byte *Map_Bri[3] = { M_Bri_Log, M_Bri_Stump, M_Bri_Rope };
//------

void (*Bri_Index[6])() = { Bri_Main, Bri_Action, Bri_Platform, Bri_Delete, Bri_Delete, Bri_Display };

//Bridge:					; XREF: Obj_Index
void Bridge(object *_obj)
{
    obj = _obj;

    //moveq	#0,d0
    //move.b	obRoutine(a0),d0
    byte routine = obj->Routine/2;

    //move.w	Bri_Index(pc,d0.w),d1
    //jmp	Bri_Index(pc,d1.w)
    (*Bri_Index[routine])();
}


//Bri_Main:	; Routine 0
void Bri_Main()
{
    //addq.b	#2,obRoutine(a0)
    obj->Routine = obj->Routine + 2;

    //move.l	#Map_Bri,obMap(a0)
    obj->Map = Map_Bri;

    //move.w	#$438E,obGfx(a0)
    obj->Gfx = 0x438E;

    //move.b	#4,obRender(a0)
    obj->Render = 4;

    //move.b	#3,obPriority(a0)
    obj->Priority = 3;
 
    //move.b	#$80,obActWid(a0)
    obj->ActionWidth = 0x80;

    //move.w	obY(a0),d2
    word bridgeY = obj->Y;

    //move.w	obX(a0),d3
    word bridgeX = obj->X;

    //move.b	0(a0),d4	; copy object number ($11) to d4
    byte bridgeID = obj->ID;

    //lea	obSubtype(a0),a2
    byte *logs = &obj->Subtype;

    //moveq	#0,d1
    //move.b	(a2),d1		; copy bridge length to d1
    byte bridgeLen = *(logs);

    //move.b	#0,(a2)+	; clear bridge length
    *(logs++) = 0;

    //move.w	d1,d0
    //lsr.w	#1,d0
    //lsl.w	#4,d0
    word scaledLen = (bridgeLen / 2) * 16;     //(HALF BRIDGE)

    //sub.w	d0,d3		; d3 is position of leftmost log
    word curLogX = bridgeX - scaledLen;

    //subq.b	#2,d1
    signed char logCount = bridgeLen - 2;       //-1 for first log (already exists as parent) and -1 additionally for loop conditions (i.e. <= 10 loops 11 times) 

    //bcs.s	Bri_Action	; don't make more if bridge has only 1 log
    if (logCount >= 0)        //should be >= ??
    {
        for (;logCount >= 0; logCount--)
        {
            //@buildloop:
	    //bsr.w	FindFreeObj
            object *log = FindFreeObj();

	    //bne.s	Bri_Action
            if (log->ID == 0)
            {
	        //addq.b	#1,obSubtype(a0)
                obj->Subtype = obj->Subtype + 1;    //add to log count/bridge length

	        //cmp.w	obX(a0),d3	; is this log the leftmost (correction: middle/parent) one?
                //bne.s	@notleftmost	; if not, branch
                if (obj->X == curLogX)
                {
		    //addi.w	#$10,d3
                    curLogX = curLogX + 16;

		    //move.w	d2,obY(a0)
                    obj->Y = bridgeY;

		    //move.w	d2,$3C(a0)
                    ptrsetobjvariableword(0x3C,obj,bridgeY);

		    //move.w	a0,d5
                    //subi.w	#$D000,d5       //objects start at 0xD000
                    //lsr.w	#6,d5
		    //andi.w	#$7F,d5
		    word obIndex = (obj - &objects[0]);

                    //move.b	d5,(a2)+
                    *(logs++) = obIndex;

       		    //addq.b	#1,obSubtype(a0)
                    obj->Subtype = obj->Subtype + 1;
                }                
	
                //@notleftmost:
	        //move.w	a1,d5
	        //subi.w	#$D000,d5
	        //lsr.w	#6,d5
	        //andi.w	#$7F,d5
                word logIndex = (log - &objects[0]);

	        //move.b	d5,(a2)+
                *(logs++) = logIndex;

	        //move.b	#$A,obRoutine(a1)
                log->Routine = 0xA;

	        //move.b	d4,0(a1)	; load bridge object (d4 = $11)
                log->ID = bridgeID;

	        //move.w	d2,obY(a1)
                log->Y = bridgeY;

	        //move.w	d2,$3C(a1)
                ptrsetobjvariableword(0x3C,log,bridgeY);
 
	        //move.w	d3,obX(a1)
                log->X = curLogX;

	        //move.l	#Map_Bri,obMap(a1)
                log->Map = Map_Bri;

	        //move.w	#$438E,obGfx(a1)
                log->Gfx = 0x438E;

	        //move.b	#4,obRender(a1)
                log->Render = 4;

	        //move.b	#3,obPriority(a1)
                log->Priority = 3;

	        //move.b	#8,obActWid(a1)
                log->ActionWidth = 8;

	        //addi.w	#$10,d3
                curLogX = curLogX + 16;
            }
            else
                break;
        }    //dbf	d1,@buildloop ; repeat d1 times (length of bridge)
    }

    Bri_Action();
}

//Bri_Action:	; Routine 2
void Bri_Action()
{
    //bsr.s	Bri_Solid
    Bri_Solid();

    //tst.b	$3E(a0)
    //beq.s	@display
    if (obj->Variables[0x3E - 0x28] != 0)
    {
        //subq.b	#4,$3E(a0)
        obj->Variables[0x3E - 0x28] = (obj->Variables[0x3E - 0x28] - 4);

	//bsr.w	Bri_Bend
        Bri_Bend();
    }
    
    //@display:
    //bsr.w	DisplaySprite
    DisplaySprite(obj);

    //bra.w	Bri_ChkDel
    Bri_ChkDel();

}   //; ||||||||||||||| S U B	R O U T	I N E |||||||||||||||||||||||||||||||||||||||


//Bri_Solid:
void Bri_Solid()
{
    //moveq	#0,d1
    //move.b	obSubtype(a0),d1
    //lsl.w	#3,d1
    word bridgeHalf = obj->Subtype * 8;

    //move.w	d1,d2
    //word  = subtype;

    //addq.w	#8,d1
    word bridgeMiddle = bridgeHalf + 8;    //additional centering for distance
    
    //add.w	d2,d2
    word bridgeLen = bridgeHalf * 2;

    //lea	(v_player).w,a1
    object *player = &objects[0];      // already defined by pre-processor

    //tst.w	obVelY(a1)
    //bmi.w	Plat_Exit
    if (player->VelocityY < 0) { /*Plat_Exit(); - aka end function*/ }
    else
    {	
        //move.w	obX(a1),d0
	//sub.w	        obX(a0),d0
        signed short distPlayerBri = player->X - obj->X;           //distance from player to bridge center log

	//add.w	d1,d0
        signed short halfDist = distPlayerBri + bridgeMiddle;      //distance from player to bridge leftmost log

	//bmi.w	Plat_Exit
        if (halfDist < 0) { /*Plat_Exit(); - aka end function*/ }              //to 'left' of bridge
        else
        {
	    //cmp.w	d2,d0
            //bcc.w	Plat_Exit
            //bra.s	Plat_NoXCheck
            if (halfDist >= bridgeLen) { /*Plat_Exit(); - aka end function*/ }  //to 'right' of bridge
	    else { Plat_NoXCheck(obj); }                                       //on bridge
	}
    }
}   //; End of function Bri_Solid


//Bri_Platform:	; Routine 4
void Bri_Platform()
{
    //bsr.s	Bri_WalkOff
    Bri_WalkOff();

    //bsr.w	DisplaySprite
    DisplaySprite(obj);

    //bra.w	Bri_ChkDel
    Bri_ChkDel();
}

//; ---------------------------------------------------------------------------
//; Subroutine allowing Sonic to walk off a bridge
//; ---------------------------------------------------------------------------

//; ||||||||||||||| S U B	R O U T	I N E |||||||||||||||||||||||||||||||||||||||


//Bri_WalkOff:				; XREF: Bri_Platform
void Bri_WalkOff()
{
    //moveq	#0,d1
    //move.b	obSubtype(a0),d1
    //lsl.w	#3,d1
    word bridgeHalf = obj->Subtype * 8;

    //move.w	d1,d2
    //addq.w	#8,d1
    word bridgeMiddle = bridgeHalf + 8;

    signed short platDist;
    //bsr.s	ExitPlatform2
    bool exited = ExitPlatform2(obj, bridgeHalf, bridgeMiddle, platDist);

    //bcc.s	locret_75BE
    if (exited == false)
    {
        //lsr.w	#4,d0
        signed short scaleDist = platDist / 16;

	//move.b	d0,$3F(a0)
        obj->Variables[0x3F - 0x28] = scaleDist;

	//move.b	$3E(a0),d0
        byte d0 = obj->Variables[0x3E - 0x28];

	//cmpi.b	#$40,d0
        //beq.s	loc_75B6
        if (d0 != 0x40)
        {
	    //addq.b	#4,$3E(a0)
            obj->Variables[0x3E - 0x28] = (obj->Variables[0x3E - 0x28] + 4);
        }

        //loc_75B6:
	//bsr.w	Bri_Bend
        Bri_Bend();

	//bsr.w	Bri_MoveSonic
        Bri_MoveSonic();
    }
    //locret_75BE:
    //rts	
}   //; End of function Bri_WalkOff

//; ||||||||||||||| S U B	R O U T	I N E |||||||||||||||||||||||||||||||||||||||


//Bri_MoveSonic:				; XREF: Bri_WalkOff
void Bri_MoveSonic()
{
    //moveq	#0,d0
    //move.b	$3F(a0),d0
    byte index = obj->Variables[0x3F - 0x28];

    //move.b	$29(a0,d0.w),d0
    byte logIndex = obj->Variables[index];

    //lsl.w	#6,d0
    //addi.l	#v_objspace&$FFFFFF,d0
    //movea.l	d0,a2
    object *log = &objects[logIndex];

    //lea	(v_player).w,a1 
    object *player = &objects[0];

    //move.w	obY(a2),d0
    word logY = log->Y;

    //subq.w	#8,d0
    word logTop = logY - 8;

    //moveq	#0,d1
    //move.b	obHeight(a1),d1
    byte playerHeight = player->Height;

    //sub.w	d1,d0
    word repositionY = logTop - playerHeight;

    //move.w	d0,obY(a1)	; change Sonic's position on y-axis
    player->Y = repositionY;

}   //rts	
//; End of function Bri_MoveSonic


//; ||||||||||||||| S U B	R O U T	I N E |||||||||||||||||||||||||||||||||||||||

//; ---------------------------------------------------------------------------
//; GHZ bridge-bending data
//; (Defines how the bridge bends	when Sonic walks across	it)
//; ---------------------------------------------------------------------------
extern byte Obj11_BendData[]; 
extern byte Obj11_BendData2[];

//Bri_Bend:				; XREF: Bri_Action; Bri_WalkOff
void Bri_Bend()
{
    //move.b	$3E(a0),d0
    byte bridgeAngle = obj->Variables[0x3E - 0x28];

    signed short sine, cosine;
    //bsr.w	CalcSine
    CalcSine(bridgeAngle, sine, cosine);

    //move.w	d0,d4
    //lea	(Obj11_BendData2).l,a4
		
    //moveq	#0,d0
    //move.b	obSubtype(a0),d0
    //lsl.w	#4,d0
    word scaledLen = obj->Subtype * 16;

    //moveq	#0,d3
    //move.b	$3F(a0),d3
    byte logCount = obj->Variables[0x3F - 0x28];

    //move.w	d3,d2
    signed short curLog = logCount;

    //add.w	d0,d3
    word bendOffset = scaledLen + logCount;

    //moveq	#0,d5
    //lea	(Obj11_BendData).l,a5
    //move.b	(a5,d3.w),d5
    byte bend1 = Obj11_BendData[bendOffset];

    //andi.w	#$F,d3
    //lsl.w	#4,d3
    word bend2Offset = (bendOffset & 0xF) * 16;

    //lea	(a4,d3.w),a3
    byte *bend2Ptr = &Obj11_BendData2[bend2Offset];

    //lea	$29(a0),a2
    byte *logIndexPtr = &obj->Variables[0];

    //loc_765C:
    for (; curLog >= 0; curLog--)
    {
        //moveq	#0,d0
	//move.b	(a2)+,d0
        byte logIndex = *(logIndexPtr++);

	//lsl.w	#6,d0
	//addi.l	#v_objspace&$FFFFFF,d0
        //movea.l	d0,a1
        object *log = &objects[logIndex];

	//moveq	#0,d0
	//move.b	(a3)+,d0
        //addq.w	#1,d0
        signed short bend2 = *(bend2Ptr++) + 1;

	//mulu.w	d5,d0
	//mulu.w	d4,d0
        //swap	d0
        signed short magnitude = (sine * (bend1 * bend2)) >> 16;

	//add.w	$3C(a1),d0
        word yLog = magnitude + ptrgetobjvariableword(0x3C,log);

	//move.w	d0,obY(a1)
        log->Y = yLog;

    }   //dbf	d2,loc_765C


    //moveq	#0,d0
    //move.b	obSubtype(a0),d0
    byte bridgeLen = obj->Subtype;

    //moveq	#0,d3
    //move.b	$3F(a0),d3
    //addq.b	#1,d3
    byte standLog = obj->Variables[0x3F - 0x28] + 1;
        
    //sub.b	d0,d3
    //neg.b	d3
    signed char logLIndex = -(standLog - bridgeLen);

    //bmi.s	locret_76CA
    if (logLIndex >= 0)
    {
	//move.w	d3,d2
	//lsl.w	#4,d3
        bend2Offset = (logLIndex * 16);

	//lea	(a4,d3.w),a3
        //adda.w	d2,a3
        bend2Ptr = &Obj11_BendData2[bend2Offset + logLIndex];

        //subq.w	#1,d2
        curLog = logLIndex - 1;

	//bcs.s	locret_76CA
        if (curLog >= 0) 
        {
            for (; curLog >= 0; curLog--)
            {
                //loc_76A4:
		//moveq	#0,d0
		//move.b	(a2)+,d0
                byte logIndex = *(logIndexPtr++);

		//lsl.w	#6,d0
		//addi.l	#v_objspace&$FFFFFF,d0
		object *log = &objects[logIndex];

                //movea.l	d0,a1
                
		//moveq	#0,d0
		//move.b	-(a3),d0
                //addq.w	#1,d0
                signed short bend2 = *(--bend2Ptr) + 1;

		//mulu.w	d5,d0
		//mulu.w	d4,d0
                //swap	d0
		signed short magnitude = (sine * (bend1 * bend2)) >> 16;

		//add.w	$3C(a1),d0
                word yLog = magnitude + ptrgetobjvariableword(0x3C,log);

		//move.w	d0,obY(a1)
                log->Y = yLog;

	    }   //dbf	d2,loc_76A4
        }
    }

    //locret_76CA:
    //rts	
}   //; End of function Bri_Bend

//Bri_ChkDel:				; XREF: Bri_Display; Bri_Platform
void Bri_ChkDel()
{
    //out_of_range	@deletebridge
    if (out_of_range(obj)) { deletebridge(); }

} //rts	
//; ===========================================================================

//@deletebridge:
void deletebridge()
{
    //moveq	#0,d2
    //lea	obSubtype(a0),a2 ; load bridge length
    byte *logs = &obj->Subtype;

    //move.b	(a2)+,d2	; move bridge length to	d2    
    //subq.b	#1,d2		; subtract 1
    signed char logCount = *(logs++) - 1;

    //bcs.s	@delparent
    if (logCount >= 0)
    {
        for (;logCount >= 0; logCount--)
        {
            //@loop:
	    //moveq	#0,d0
            //move.b	(a2)+,d0
            byte logIndex = *(logs++);

            //lsl.w	#6,d0
            //addi.l	#v_objspace&$FFFFFF,d0
            //movea.l	d0,a1
            object *log = &objects[logIndex];

	    //cmp.w	a0,d0
            if (log != obj)
            {
	        //beq.s	@skipdel
	        //bsr.w	DeleteChild
                DeleteChild(log);
            }
	}
        //@skipdel:
    }   //dbf	d2,@loop ; repeat d2 times (bridge length)

    //@delparent:
    //bsr.w	DeleteObject
    DeleteObject(obj);
}   //rts	


//; ===========================================================================

//Bri_Delete:	; Routine 6, 8
void Bri_Delete()
{
    //bsr.w	DeleteObject
    DeleteObject(obj);

}   //rts	
//; ===========================================================================

//Bri_Display:	; Routine $A
void Bri_Display()
{
    //bsr.w	DisplaySprite
    DisplaySprite(obj);

}   //rts	
